package service

import (
	"admin-api/app/dao"
	"admin-api/app/models/entity"
	"admin-api/app/models/request"
	"admin-api/app/models/response"
	"admin-api/app/models/vo"
	"admin-api/core"
	"admin-api/utils"
	"gitee.com/molonglove/goboot/gorm"
	"sort"
	"time"
)

var Menu = new(MenuService)

type MenuService struct{}

// Tree 菜单树
func (m *MenuService) Tree() ([]*response.MenuTree, *response.BusinessError) {
	var (
		recursionBuild func(pId int64, data []entity.Menu) []*response.MenuTree
		tree           []*response.MenuTree
		all            []entity.Menu
		err            error
	)
	// 递归构建树
	recursionBuild = func(pId int64, data []entity.Menu) []*response.MenuTree {
		var children []*response.MenuTree
		for _, item := range data {
			if pId == item.ParentId {
				child := &response.MenuTree{
					Key:   item.MenuId,
					Label: item.MenuName,
				}
				child.Children = recursionBuild(item.MenuId, data)
				children = append(children, child)
			}
		}
		return children
	}
	if all, err = dao.Menu.All(); err != nil {
		core.Log.Error("获取菜单数据发生异常：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取菜单数据失败")
	}
	if len(all) <= 0 {
		return make([]*response.MenuTree, 0), nil
	}
	tree = recursionBuild(0, all)
	return tree, nil
}

// Table 表格数据查询
func (m *MenuService) Table(param *request.MenuTableQueryRequest) ([]response.MenuTableResponse, *response.BusinessError) {
	var (
		recursionBuild func(pId int64, data []entity.Menu) []response.MenuTableResponse
		result         []response.MenuTableResponse
		all            []entity.Menu
		err            error
	)
	// 递归构建树
	recursionBuild = func(pId int64, data []entity.Menu) []response.MenuTableResponse {
		var children []response.MenuTableResponse
		for _, item := range data {
			if pId == item.ParentId {
				child := response.MenuTableResponse{
					MenuId:     item.MenuId,
					MenuName:   item.MenuName,
					MenuCode:   item.MenuCode,
					ParentId:   item.ParentId,
					OrderNum:   item.OrderNum,
					IsPublic:   item.IsPublic,
					IsShow:     item.IsShow,
					Icon:       item.Icon,
					MenuPath:   item.MenuPath,
					Remark:     item.Remark,
					CreateTime: item.CreateTime,
				}
				child.Children = recursionBuild(item.MenuId, data)
				children = append(children, child)
			}
		}
		return children
	}
	if all, err = dao.Menu.All(); err != nil {
		core.Log.Error("获取菜单数据发生异常：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取菜单数据失败")
	}
	if len(all) <= 0 {
		return nil, nil
	}
	result = recursionBuild(0, all)
	return result, nil
}

// Create 菜单创建
func (m *MenuService) Create(param *request.MenuCreateRequest) *response.BusinessError {
	var (
		menu entity.Menu
		err  error
		num  int64
	)
	// 检测菜单名称是否唯一
	if err = core.DB.Builder().
		Select(gorm.Count("1")).
		From("sys_menu").
		Where(
			gorm.Eq("menu_code", param.MenuCode),
			gorm.Eq("parent_id", param.ParentId),
		).
		QExecute(&num).Error; err != nil || num > 0 {
		if err != nil {
			core.Log.Error("存在相同的资源名称: %s", err.Error())
		}
		return response.CustomBusinessError(response.Failed, "存在相同的资源名称")
	}
	// 保存菜单数据
	_ = utils.StructCopy(param, &menu)
	menu.CreateTime = time.Now()
	if err = core.DB.Create(&menu).Error; err != nil {
		return response.CustomBusinessError(response.Failed, "创建菜单失败")
	}
	core.Log.Info("创建菜单[%d:%s]成功", menu.MenuId, param.MenuName)
	return nil
}

// Update 菜单修改
func (m *MenuService) Update(param *request.MenuUpdateRequest) *response.BusinessError {
	var (
		old entity.Menu
		err error
		num int64
	)
	// 检测菜单名称是否唯一
	if err = core.DB.Builder().
		Select(gorm.Count("1")).
		From("sys_menu").
		Where(
			gorm.Eq("menu_name", param.MenuName),
			gorm.Eq("menu_id", param.MenuId),
		).
		QExecute(&num).
		Error; err != nil || num > 0 {
		if err != nil {
			core.Log.Error("查询资源信息错误:%s", err.Error())
		}
		return response.CustomBusinessError(response.Failed, "存在相同的资源名称")
	}
	// 获取修改的数据
	if old, err = dao.Menu.GetMenuById(param.MenuId); err != nil {
		core.Log.Error("当前菜单[%d]不存在", param.MenuId)
		return response.CustomBusinessError(response.Failed, "当前菜单不存在")
	}
	// 保存菜单数据
	param.To(&old)
	if err = core.DB.Save(&old).Error; err != nil {
		core.Log.Error("更新菜单[%d]:%s", param.MenuId, err.Error())
		return response.CustomBusinessError(response.Failed, "更新菜单失败")
	}
	return nil
}

// Delete 菜单删除
func (m *MenuService) Delete(menuId int64, updateName string) *response.BusinessError {
	var (
		err error
		num int64
	)
	// 菜单是否存在子菜单
	if err = core.DB.Builder().
		Select(gorm.Count("1")).
		From("sys_menu").
		Where(gorm.Eq("parent_id", menuId)).
		QExecute(&num).
		Error; err != nil || num > 0 {
		if err != nil {
			core.Log.Error("查询菜单出错: %s", err.Error())
		}
		return response.CustomBusinessError(response.Failed, "菜单是否存在子菜单")
	}
	// 菜单是否已经分配角色
	if err = core.DB.Builder().
		Select(gorm.Count("role_id")).
		From("sys_role_menu").
		Where(gorm.Eq("menu_id", menuId)).
		QExecute(&num).
		Error; err != nil || num > 0 {
		if err != nil {
			core.Log.Error("查询菜单出错: %s", err.Error())
		}
		return response.CustomBusinessError(response.Failed, "菜单已经分配角色")
	}
	if err = core.DB.Builder().
		Delete().
		From("sys_role_menu").
		Where(gorm.Eq("menu_id", menuId)).
		DExecute().
		Error; err != nil {
		core.Log.Error("删除菜单失败：%s", err.Error())
		return response.CustomBusinessError(response.Failed, "删除菜单失败")
	}
	return nil
}

// Info 菜单详情
func (m *MenuService) Info(menuId int64) (*response.MenuInfoResponse, *response.BusinessError) {
	var (
		menu entity.Menu
		err  error
	)
	if menu, err = dao.Menu.GetMenuById(menuId); err != nil {
		core.Log.Info("获取菜单失败：%s", menuId)
		return nil, response.CustomBusinessError(response.Failed, "获取菜单失败")
	}
	return response.NewMenuInfo(&menu), nil
}

// UserRouter 用户路由
func (m *MenuService) UserRouter(userId int64, roleId int64) ([]response.UserRouterResponse, *response.BusinessError) {
	var (
		buildTree func(data []response.UserRouterResponse, parentId int64) []response.UserRouterResponse
		result    []response.UserRouterResponse
		err       error
	)
	// 构建Tree
	buildTree = func(data []response.UserRouterResponse, parentId int64) []response.UserRouterResponse {
		var children []response.UserRouterResponse
		for _, item := range data {
			if parentId == item.ParentId {
				item.Children = buildTree(data, item.MenuId)
				children = append(children, item)
			}
		}
		// 排序
		sort.Slice(children, func(i, j int) bool {
			return children[i].MenuSort < children[j].MenuSort
		})
		return children
	}
	// 构建查询条件
	condition := make(map[string]any)
	if userId == vo.SUPER_USER_ID {
		condition["IsAll"] = 0
	} else {
		condition["RoleId"] = roleId
		if roleId == 0 {
			condition["UserId"] = userId
		}
	}
	if err = core.DB.Namespace("menu").
		DQuery("selectMenuByRoles", condition).
		TSelect(&result).
		Error; err != nil {
		core.Log.Error("查询用户的路由信息发生异常：%s", err.Error())
		return nil, response.CustomBusinessError(response.Failed, "获取用户路由失败")
	}
	return buildTree(result, 0), nil

}
